<?php

	namespace org\tekuna\framework\request;

	use org\tekuna\core\application\Application;
	use org\tekuna\core\context\Context;
	use org\tekuna\core\configuration\ConfigurationElement;

	use org\tekuna\framework\context\ContextObjectBuilder;
	use org\tekuna\framework\filter\Filter;
	use org\tekuna\framework\filter\data\NoSpecialCharsFilter;


	/**
	 * This class provides a basic infrastructure for both HTTP and CLI requests.
	 * A default filter and the import encoding can be set. The static builder method
	 * is used when initializing the Request object for the application context.
	 */
	abstract class Request implements ContextObjectBuilder {

		protected
			$sImportEncoding = 'UTF-8',
			$objDefaultFilter = NULL;


		/**
		 * This builder method is called from the framework when initializing the
		 * application context. It returns a HttpRequest or a CliRequest, according
		 * to the type of request
		 * 
		 * @param Context $objContext the partial application context
		 * @param ConfigurationElement $objContextConfigElement the defining element in the configuration
		 */
		public static function buildContextObject(Context $objContext, ConfigurationElement $objContextConfigElement) {

			if (Application :: isHttpRequest()) {

				return new HttpRequest();
			}
			else {

				return new CliRequest();
			}
		}


		public function __construct() {

			// check for the mb extension
			if (! extension_loaded('mbstring')) {

				throw new RequestException("The 'mbstring' extension is not loaded. This is required for Tekuna because of the real UTF-8 support.");
			}

			// set UTF-8 as default internal encoding
			mb_internal_encoding('UTF-8');

			// set default filter
			$this -> objDefaultFilter = new NoSpecialCharsFilter();

			// run concrete initializations
			$this -> init();
		}


		abstract protected function init();


		/**
		 * Set the default filter that is applied, if no special filter
		 * for a specific GET or POST field is set.
		 *
		 * ATTENTION: Use this method only as last possibility. For security
		 * reasons it is always better to use the setGetFilter() or
		 * setPostFilter() methods of the HttpRequest
		 * to set individual filters for each parameter.
		 *
		 * @param Filter $objFilter the new filter object
		 */
		public function setDefaultFilter(Filter $objFilter) {

			$this -> objDefaultFilter = $objFilter;
		}


		/**
		 * @return Filter returns the current active default filter for GET and POST values
		 */
		public function getDefaultFilter() {

			return $this -> objDefaultFilter;
		}


		/**
		 * Set the encoding of the request data. This value defaults to UTF-8.
		 * If another encoding is set, the data is converted to the internally
		 * used UTF-8 encoding.
		 *
		 * @param string $sEncoding the encoding of the request data
		 */
		public function setImportEncoding($sEncoding) {

			$this -> sImportEncoding = $sEncoding;
		}


		/**
		 * @return string returns the currently set import encoding
		 */
		public function getImportEncoding() {

			return $this -> sImportEncoding;
		}


		/**
		 * Applies a given filter to the given data. The data might be an array (consisting of more arrays or strings) or a string.
		 *
		 * @param mixed $arrData
		 * @param Filter $objFilter
		 */
		public function applyFilterRecursive($arrData, Filter $objFilter) {

			if (is_array($arrData)) {

				$arrReturn = array();

				foreach ($arrData as $mKey => $mValue) {

					$mValue = $this -> applyFilterRecursive($mValue, $objFilter);

					$arrReturn[$mKey] = $mValue;
				}

				return $arrReturn;
			}
			else {

				// adjust encoding of the data if necessary
				if ($this -> getImportEncoding() != mb_internal_encoding()) {

					$arrData = mb_convert_encoding($arrData, mb_internal_encoding(), $this -> getImportEncoding());
				}

				// decode escaped values if magic_quotes_gpc is enabled
				if (get_magic_quotes_gpc()) {

					$arrData = stripslashes($arrData);
				}

				// filter the data
				return $objFilter -> filter($arrData);
			}
		}
	}

